//Set this var in the bookmarklet to load it from a different location
if(typeof tEdPath === "undefined") tEdPath = "http://templateed.com/";

/**
 * tEd - template Editor
 * 
 * MIT LICENSE
 * 
 * Date: 21 Oct 2008
 *
 * @projectDescription A local HTML & CSS in-browser editor for Firefox 
 * Tested only in Firefox Windows, may consider other platforms if faster JS + local save file support
 * 
 * @author Simon Brown
 *
 * Thanks to:
 * 
 * 
 * 
 General Structure:
 

	    
"opt" = blatant place to optimise
    
    
    
    
    
    ideas:
    http://www.niallkennedy.com/blog/2007/01/ajax-performance-local-storage.html#firefox2  


	cache control on ted.lib
	http://www.thinkvitamin.com/features/webapps/serving-javascript-fast
	<?php
	header("Expires: ".gmdate("D, d M Y H:i:s", time()+315360000)." GMT");
	header("Cache-Control: max-age=315360000");
	?>
	
	//todo highlight padding and margin on elements, perhaps when hovering over them, or perhaps when hovering over the selector or soemthing in thecss
    
    
*/



/*****************************/
/* LOADING SCREEN            */    
/*****************************/

//add div to screen
if(tEdLoadingDiv === undefined) {

    //thanks http://www.javascriptkit.com/javatutors/navigator.shtml
    //should really test for version numbers
    if (!/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)) { //test for Firefox/x.x or Firefox x.x (ignoring remaining digits);
        alert("Sorry, tEd (http://templateed.com/) only works in Firefox.");
		throw new Error("Unsupported browser");
    }

	if (document.styleSheets.length < 1) {
	    alert("The document must contain an external stylesheet for tEd to work.");
		throw new Error("This document contains no style sheets");
	}
    

    var tEdLoadingHtml = "<div id='tEdOverlay' style='background:#000;z-index:100000;position:fixed;top:0;left:0;width:100%;height:100%;'></div>" +
                         "<div id='tEdLoadingStatus' style='z-index:150000;position:fixed;color:#fff;font-weight:bold;font-family:Arial;font-size:15px;fontleft:0;top:0;width:100%;height:50%;top:40%;text-align:center;'>" +
                         "  <!--<img src='http://templateed.com/images/ajaxloader.gif' />" +
                         "  <br /><br />-->tEd - Loading libraries (~94k) <br />" +
                         "  <span id='tEdLoadingDots'></span><br /><div id='IT_IS_LOADED' title='check the sheet has loaded'></div>" +
                         "</div>";
                         
    var tEdLoadingDiv = document.createElement("DIV");
    tEdLoadingDiv.id = "tEdLoadingDiv";
    tEdLoadingDiv.innerHTML = tEdLoadingHtml;
    document.getElementsByTagName("html")[0].appendChild(tEdLoadingDiv);
    var tEdOverlay = document.getElementById("tEdOverlay");
    tEdOverlay.style.opacity = "0.1";
    
    //loading animation
    var tEdLoadingDotsTimer = setInterval(function() {
        var dots = document.getElementById("tEdLoadingDots");
        
        dots.innerHTML = dots.innerHTML.length > 10 ?  "" :   dots.innerHTML + ".";
        if((parseFloat(tEdOverlay.style.opacity) < 0.6)) {
            tEdOverlay.style.opacity = ""+(parseFloat(tEdOverlay.style.opacity) + 0.2);
        }   //WHAT 'BOUT LOADING CSS?     - add to sheetup onload event?...
        
        else {
            //start loading scripts after it has faded in
            if(typeof tEdLoadStuffTimer === "undefined")
                tEdLoadStuffTimer = setTimeout("loadStuff()", 0);
        }
    }, 55);
}










typeof window.tEd !== "undefined" ? (function(){throw new Error("tEd loaded already")})() : 
(function(){	

	
/*****************************/
/* PRIVATE VARIABLES         */    
/*****************************/

	//Paths and filenames
var local =  !window.location.href.indexOf("file:///"),
	localPath = "C:\\websites\\ted tests",
	tEdCssFilename = "ted.css",		
	
	//Local data
	sheets = [], 		
	sheetsHref = [],
	currentSheet = 0,
	time = 0,
	outlined = false,
	
	//Windows		 
	windowPositions = [ "#tEdCssWindow", "#tEdHtmlWindow", "#tEdCss", "#tEdHtml", 
	 					"#tEdHtmlLineNumbers div",  "#tEdCssLineNumbers div" ],
 	cssLineNumber = 1,
	htmlLineNumber = 1,
	numberOfLines = 400,
	
	editingInclude = false,
	

	//Keywords hanks http://code.google.com/p/syntaxhighlighter/
	cssKeywords =["ascent", "azimuth", "background","background-attachment", "background-color", "background-image", "background-position",
				"background-repeat",  "baseline", "bbox", "border-collapse", "border-color", "border-spacing", "border-style", "border-top",
				"border-right", "border-bottom", "border-left", "border-top-color", "border-right-color", "border-bottom-color", "border-left-color",
				"border-top-style", "border-right-style", "border-bottom-style", "border-left-style", "border-top-width", "border-right-width",
				"border-bottom-width", "border-left-width", "border-width", "border", "cap-height", "caption-side", "centerline", "clear", "clip", "color",
				"content", "counter-increment", "counter-reset", "cue-after", "cue-before", "cue", "cursor", "definition-src", "descent", "direction", "display",
				"elevation", "empty-cells", "float", "font-size-adjust", "font-family", "font-size", "font-stretch", "font-style", "font-variant", "font-weight", "font",
				"height", "letter-spacing", "line-height", "list-style-image", "list-style-position", "list-style-type", "list-style", "margin-top",
				"margin-right", "margin-bottom", "margin-left", "margin", "marker-offset", "marks", "mathline", "max-height", "max-width", "min-height", "min-width", "orphans",
				"outline-color", "outline-style", "outline-width", "outline", "overflow", "padding-top", "padding-right", "padding-bottom", "padding-left", "padding", "page",
				"page-break-after", "page-break-before", "page-break-inside", "pause", "pause-after", "pause-before", "pitch", "pitch-range", "play-during", "position",
				"quotes", "richness", "size", "slope", "src", "speak-header", "speak-numeral", "speak-punctuation", "speak", "speech-rate", "stemh", "stemv", "stress",
				"table-layout", "text-align", "text-decoration", "text-indent", "text-shadow", "text-transform", "unicode-bidi", "unicode-range", "units-per-em",
				"vertical-align", "visibility", "voice-family", "volume", "white-space", "widows", "width", "widths", "word-spacing", "x-height", "z-index"],
	
	
	cssValues = ["above", "absolute", "all", "always", "aqua", "armenian", "attr", "aural", "auto", "avoid", "baseline", "behind", "below", "bidi-override", "black", "blink", "block", "blue", "bold", "bolder",
				"both", "bottom", "braille", "capitalize", "caption", "center", "center-left", "center-right", "circle", "close-quote", "code", "collapse", "compact", "condensed",
				"continuous", "counter", "counters", "crop", "cross", "crosshair", "cursive", "dashed", "decimal", "decimal-leading-zero", "default", "digits", "disc", "dotted", "double",
				"embed", "embossed", "e-resize", "expanded", "extra-condensed", "extra-expanded", "fantasy", "far-left", "far-right", "fast", "faster", "fixed", "format", "fuchsia",
				"gray", "green", "groove", "handheld", "hebrew", "help", "hidden", "hide", "high", "higher", "icon", "inline-table", "inline", "inset", "inside", "invert", "italic",
				"justify", "landscape", "large", "larger", "left-side", "left", "leftwards", "level", "lighter", "lime", "line-through", "list-item", "local", "loud", "lower-alpha",
				"lowercase", "lower-greek", "lower-latin", "lower-roman", "lower", "low", "ltr", "marker", "maroon", "medium", "message-box", "middle", "mix", "move", "narrower",
				"navy", "ne-resize", "no-close-quote", "none", "no-open-quote", "no-repeat", "normal", "nowrap", "n-resize", "nw-resize", "oblique", "olive", "once", "open-quote", "outset",
				"outside", "overline", "pointer", "portrait", "pre", "print", "projection", "purple", "red", "relative", "repeat", "repeat-x", "repeat-y", "rgb", "ridge", "right", "right-side",
				"rightwards", "rtl", "run-in", "screen", "scroll", "semi-condensed", "semi-expanded", "separate", "se-resize", "show", "silent", "silver", "slower", "slow",
				"small", "small-caps", "small-caption", "smaller", "soft", "solid", "speech", "spell-out", "square", "s-resize", "static", "status-bar", "sub", "super", "sw-resize",
				"table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", "table-row", "table-row-group", "teal",
				"text-bottom", "text-top", "thick", "thin", "top", "transparent", "tty", "tv", "ultra-condensed", "ultra-expanded", "underline", "upper-alpha", "uppercase", "upper-latin",
				"upper-roman", "url", "visible", "wait", "white", "wider", "w-resize", "x-fast", "x-high", "x-large", "x-loud", "x-low", "x-slow", "x-small", "x-soft", "xx-large", "xx-small", "yellow"]

	
	//for a popup insert symbol thing - thanks wikipedia
	entities = ["quot", "amp", "apos", "lt", "gt", "quot", "amp", "apos", "nbsp", "iexcl", "cent", "pound", "curren", "yen", "brvbar", "sect", "uml",
	 "copy", "ordf", "laquo", "not", "shy", "reg", "macr", "deg", "plusmn", "sup2", "sup3", "acute", "micro", "para", "middot", "cedil", "sup1", "ordm", "raquo",
	  "frac14", "frac12", "frac34", "iquest", "Agrave", "Aacute", "Acirc", "Atilde", "Auml", "Aring", "AElig", "Ccedil", "Egrave", "Eacute", "Ecirc", "Euml", 
	  "Igrave", "Iacute", "Icirc", "Iuml", "ETH", "Ntilde", "Ograve", "Oacute", "Ocirc", "Otilde", "Ouml", "times", "Oslash", "Ugrave", "Uacute", "Ucirc", "Uuml", 
	  "Yacute", "THORN", "szlig", "agrave", "aacute", "acirc", "atilde", "auml", "aring", "aelig", "ccedil", "egrave", "eacute", "ecirc", "euml", "igrave", "iacute", 
	  "icirc", "iuml", "eth", "ntilde", "ograve", "oacute", "ocirc", "otilde", "ouml", "divide", "oslash", "ugrave", "uacute", "ucirc", "uuml", "yacute", "thorn", 
	  "yuml", "OElig", "oelig", "Scaron", "scaron", "Yuml", "fnof", "circ", "tilde", "Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta", "Eta", "Theta", "Iota", 
	  "Kappa", "Lambda", "Mu", "Nu", "Xi", "Omicron", "Pi", "Rho", "Sigma", "Tau", "Upsilon", "Phi", "Chi", "Psi", "Omega", "alpha", "beta", "gamma", "delta", 
	  "epsilon", "zeta", "eta", "theta", "iota", "kappa", "lambda", "mu", "nu", "xi", "omicron", "pi", "rho", "sigmaf", "sigma", "tau", "upsilon", "phi", "chi", 
	  "psi", "omega", "thetasym", "upsih", "piv", "ensp", "emsp", "thinsp", "zwnj", "zwj", "lrm", "rlm", "ndash", "mdash", "lsquo", "rsquo", "sbquo", "ldquo", 
	  "rdquo", "bdquo", "dagger", "Dagger", "bull", "hellip", "permil", "prime", "Prime", "lsaquo", "rsaquo", "oline", "frasl", "euro", "image", "weierp", "real", 
	  "trade", "alefsym", "larr", "uarr", "rarr", "darr", "harr", "crarr", "lArr", "uArr", "rArr", "dArr", "hArr", "forall", "part", "exist", "empty", "nabla", 
	  "isin", "notin", "ni", "prod", "sum", "minus", "lowast", "radic", "prop", "infin", "ang", "and", "or", "cap", "cup", "int", "there4", "sim", "cong", "asymp", 
	  "ne", "equiv", "le", "ge", "sub", "sup", "nsub", "sube", "supe", "oplus", "otimes", "perp", "sdot", "lceil", "rceil", "lfloor", "rfloor", "lang", "rang", 
	  "loz", "spades", "clubs", "hearts", "diams"],  	
	  
	//for highlighting - 3 removed to fix it  
	entitiesReplace = ["quot", "amp", "apos", /*"lt", "gt",*/ "quot", /*"amp",*/ "apos", "nbsp", "iexcl", "cent", "pound", "curren", "yen", "brvbar", "sect", "uml",
	 "copy", "ordf", "laquo", "not", "shy", "reg", "macr", "deg", "plusmn", "sup2", "sup3", "acute", "micro", "para", "middot", "cedil", "sup1", "ordm", "raquo",
	  "frac14", "frac12", "frac34", "iquest", "Agrave", "Aacute", "Acirc", "Atilde", "Auml", "Aring", "AElig", "Ccedil", "Egrave", "Eacute", "Ecirc", "Euml", 
	  "Igrave", "Iacute", "Icirc", "Iuml", "ETH", "Ntilde", "Ograve", "Oacute", "Ocirc", "Otilde", "Ouml", "times", "Oslash", "Ugrave", "Uacute", "Ucirc", "Uuml", 
	  "Yacute", "THORN", "szlig", "agrave", "aacute", "acirc", "atilde", "auml", "aring", "aelig", "ccedil", "egrave", "eacute", "ecirc", "euml", "igrave", "iacute", 
	  "icirc", "iuml", "eth", "ntilde", "ograve", "oacute", "ocirc", "otilde", "ouml", "divide", "oslash", "ugrave", "uacute", "ucirc", "uuml", "yacute", "thorn", 
	  "yuml", "OElig", "oelig", "Scaron", "scaron", "Yuml", "fnof", "circ", "tilde", "Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta", "Eta", "Theta", "Iota", 
	  "Kappa", "Lambda", "Mu", "Nu", "Xi", "Omicron", "Pi", "Rho", "Sigma", "Tau", "Upsilon", "Phi", "Chi", "Psi", "Omega", "alpha", "beta", "gamma", "delta", 
	  "epsilon", "zeta", "eta", "theta", "iota", "kappa", "lambda", "mu", "nu", "xi", "omicron", "pi", "rho", "sigmaf", "sigma", "tau", "upsilon", "phi", "chi", 
	  "psi", "omega", "thetasym", "upsih", "piv", "ensp", "emsp", "thinsp", "zwnj", "zwj", "lrm", "rlm", "ndash", "mdash", "lsquo", "rsquo", "sbquo", "ldquo", 
	  "rdquo", "bdquo", "dagger", "Dagger", "bull", "hellip", "permil", "prime", "Prime", "lsaquo", "rsaquo", "oline", "frasl", "euro", "image", "weierp", "real", 
	  "trade", "alefsym", "larr", "uarr", "rarr", "darr", "harr", "crarr", "lArr", "uArr", "rArr", "dArr", "hArr", "forall", "part", "exist", "empty", "nabla", 
	  "isin", "notin", "ni", "prod", "sum", "minus", "lowast", "radic", "prop", "infin", "ang", "and", "or", "cap", "cup", "int", "there4", "sim", "cong", "asymp", 
	  "ne", "equiv", "le", "ge", "sub", "sup", "nsub", "sube", "supe", "oplus", "otimes", "perp", "sdot", "lceil", "rceil", "lfloor", "rfloor", "lang", "rang", 
	  "loz", "spades", "clubs", "hearts", "diams"],  	
	  
	  
						
						
						
						
						
						
						
						
	lorem = "m ipsum dolor sit amet, consectetur adipisicing elit, sed do<br> eiusmod tempor incididunt ut labore et dolore magna <br>aliqua. Ut enim ad minim veniam, "+
			"quis nostrud exercitation<br> ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute<br> irure dolor in reprehenderit in voluptate velit esse<br> cillum "+
			"dolore eu fugiat nulla pariatur.<br> Excepteur sint occaecat cupidatat non proident,<br> sunt in culpa qui officia deserunt mollit anim id est laborum."
	
	
	//Cached 
	br = document.createElement('br')
	htmlTyped = "",
	cssTyped = "",
	cssIndentNextLine = false,
	cssSizeMode = false
	;
	
	var currentAutoCompleteList = cssKeywords;
	
/****************************/
/* INIT                     */     
/****************************/

//setup tEd
window.tEd = function () {
	init();		
};		
//cache for load function to run
var tEdToLoad = tEd;

window.loadStuff = function() {
    //get the libs and run tEd on load
    function loadScript(url, todo) {
        var script = document.createElement('script');
            script.setAttribute('src', tEdPath + "lib/" + url);
            script.onload = todo;
        document.getElementsByTagName("head")[0].appendChild(script);	
    }
    
    function loadCSS(url, todo) {    
        head = document.getElementsByTagName("head")[0]      
        cssNode = document.createElement('link');
        cssNode.type = 'text/css';
        cssNode.rel =  'stylesheet';
        cssNode.href = tEdPath + "ted.css";
        cssNode.media= 'screen';      
        head.appendChild(cssNode);        
        cssNode = cssNode.sheet; 
            
            
        if(cssNode.onload) {
            cssNode.onload = todo;
        } else {                
            //need to check later to see if it is loaded
            var testCss = setInterval(function() {
                if(document.getElementById("IT_IS_LOADED").style.color == "#123456") {
                    todo();                
                    clearInterval(testCss);
                }
            } , 20);    
        }
    }
    
    //load it async to be faster...
    function loadScripts(arrScripts, todo)
    {    
        document.getElementById("tEdLoadingStatus").innerHTML += " loaded<br />" + arrScripts[0];
        if(arrScripts.length > 1) {       
            if(arrScripts[0].search(/\.css$/) > 0) {
                loadCSS(arrScripts.shift() , function(){ loadScripts( arrScripts ) });
                
            } else {
                loadScript( arrScripts.shift() , function(){ loadScripts( arrScripts ) });
            }
        } else {    
            loadScript( arrScripts.shift() , tEdToLoad  );   
        }
    }
    
    //put css to load first
    loadScripts([        
        "ted.css",
        "sheetup.packed.js",
        "jquery-1.2.6.pack.js",
        "jquery-ui-personalized-1.6rc2.packed.js",
        "jquery.rightClick-5.js",
        "jquery.contentmenu.r2-5.js",
        "jquery.jcontext.js",
        "jquery.cookie.js"
    ]);
}


/****************************/
/* PUBLIC                   */     
/****************************/
window.tEd.prototype = {
	version: "0.01a"
	//perhaps could have some log here or something	
};
tEd = tEd.prototype;





function init(){

    //Hide loading screen
    clearTimeout(tEdLoadingDotsTimer);    
    $("#tEdOverlay, #tEdLoadingStatus").fadeOut( "slow", function() { $(tEdLoadingDiv).remove();});
    

	log("Initiating ted...");
	
	/****************************/
	/* CSS AND HTML             */
	/****************************/
	ss.fn.debug = false;
	//ss(tEdPath + tEdCssFilename, "tEdStyles", $("html")[0])
	
	
	$("html").prepend(
	'<div id="tEd">' +	
		//Extra windows				
		'<div id="tEdColourPicker"></div>' +
		'<div id="tEdHtmlEntities">' +
		    '<span class="tEdClose">x</span>' +
		'</div>' +

		//Menus
		'<div class="tEdRightClickMenu" id="tEdCssRightClickMenu">' +
			'<ul>' +
				'<li><a id="tEdAddRule" href="#">Add Rule by Click</a></li>' +
				'<li><a id="tEdFindRule" href="#">Find Rule</a></li>' +
				'<li><a id="tEdCssFormat" href="#">Format</a></li>' +
				'<li><a id="tEdDivOutline" href="#">Outline</a></li>' +
			'</ul>' +
		'</div>' +
		'<div class="tEdRightClickMenu" id="tEdHtmlRightClickMenu">' +
			'<ul>' +
				'<li id="tEdHtmlEntityInsert"><a href="#">Insert Symbol</a></li>' +
				'<li id="tEdHtmlImage"><a href="#">Insert Image</a></li>' +
				'<li id="tEdHtmlFormat"><a href="#">Format</a></li>' +
			'</ul>' +
		'</div>' +
		'<div id="tEdMainMenu"><div id="tEdTab">tEd</div>' +
			'<a href="#" id="tEdMenuCss">Css Ed</a>' +
			'<a href="#" id="tEdMenuHtml">Html Ed</a>' +
			'<a href="#" id="tEdSave">Save</a>' +
			'<a href="#" id="tEdSavePath">Path</a>' +
			'<a href="#" id="tEdReset">Reset Windows</a>' +
			'<a href="#" id="tEdOpacity">Opacity</a>' +
			'<a href="#" id="tEdCompact">Compact</a>' +
			'<a href="#" id="tEdAbout">About</a>' +
		'</div>' +

		//Floating Css Window
		'<div id="tEdCssWindow">' +
			'<span class="tEdHandle">tEd Css</span>' +
			'<span class="tEdClose">x</span>' +
			'<ol id="tEdSheetsMenu"></ol>' +
			'<div class="tEdLineNumbers" id="tEdCssLineNumbers"><div></div></div>' +
			'<div contenteditable="true" id="tEdCss"></div>' +
			'<span class="tEdStatus">Status bar</span>' +
		'</div>' +

		//Floating Html window
		'<div id="tEdHtmlWindow"> <!-- this will load the html from a file and save it back there -->' +
			'<span class="tEdHandle">tEd Html</span>' +
			'<span class="tEdClose">x</span>' +
			'<ol id="tEdHtmlMenu">' +
				'<li id="tEdOpenHtml"><a href="#">Open</a></li>' +
				'<li id="tEdFontSize"><a href="#">Font Size</a></li>' +
				'<li id="tEdBackground"><a href="#">Background</a></li>' +
				'<li id="tEdBackgroundToggle"><a href="#">Bg Toggle</a></li>' +
			'</ol>' +
			'<div class="tEdLineNumbers" id="tEdHtmlLineNumbers"><div></div></div>' +
			'<div contenteditable="true" id="tEdHtml"></div>' +
			'<span class="tEdStatus">Status bar      Loading: 5%</span>' +
		'</div>' +		
		
	'</div>');
	

	
	/****************************/
	/* CACHE JQUERY SELECTIONS  */
	/****************************/
	$css = $('#tEdCss');
	$html = $('#tEdHtml');
	$menu = $("#tEdCssRightClickMenuu");
	cssNumbers = $("#tEdCssLineNumbers")[0];
	htmlNumbers = $("#tEdHtmlLineNumbers")[0];
	$cssNumbersInner = $("#tEdCssLineNumbers  div");
	$htmlNumbersInner = $("#tEdHtmlLineNumbers  div");
	loadState();
	
		
	/****************************/
	/* LINENUMBERS              */
	/****************************/
	lineNumbers();
	setInterval(updateLineNumbers, 60000);
		
	/****************************/
	/* CSS, HTML AND CSS MENU   */
	/****************************/
	var sheetIndex = 0;
	
	//each stylesheet
	for (var i = 0; i < ss.ds.length; i++) { 
		var title, css, $menuLink;
		
		//Catch auth errors on accessing external css 	
		try {
		    
		    //skip inline styles
		    if(ss.ds[i].href === null) {
		        continue;
		    }
		    
		
			//Skip tEd styles
			if (ss.ds[i].href.indexOf(tEdCssFilename) == -1) {
			
				//setup text of link
				title = ss.ds[i].href.substr(ss.ds[i].href.lastIndexOf("/") + 1);
				if (ss.ds[i].title) 
					title += " (" + ss.ds[i].title + ")";
				
				
				//Build menu link	
				$menuLink = $('<li><a href="#" title="' + ss.ds[i].href.substr(8).replace(/%20/, " ") + '">' + title + '</a></li>');
				$("#tEdSheetsMenu").append($menuLink);
				$menuLink.data("sheetIndex", sheetIndex++); //associate link with sheet	
				css = $.ajax({
					url: ss.ds[i].href, 
					async: false
				}).responseText.replace(/\r\n|\n/g, "<br>")+"<br>"; //it seems to want a new line at the end
				
				//Add sheet text to sheets array containing text of css files
				sheets.push(css);         ///////////////////////////////////////////////////////////////////////////////////////////////MAKE ANEW DIV INSTEAED!!!!!!!!!
				sheetsHref.push(ss.ds[i].href); //save paths in - if any more info needed make a new obj for it
				//Add menu button click events
				$menuLink.click(function(e){
					e.preventDefault();
					switchCssTab($(this).data("sheetIndex"));
					cssNumbers.scrollTop = $css[0].scrollTop;
				});
			}
		} 
		catch (e) {
			if (ss.ds[i].href.indexOf(tEdCssFilename) == -1) 
				log("Skipping external sheet" + ss.ds[i].href);
		    
		}
		
	}
	
	//Make sure we load up a sheet on init
	openCss(sheets[currentSheet]);
	openHtml();
	
	
	
	
	
	
	/****************************/
	/* MAIN WINDOW SETUP        */
	/****************************/
	
	//Stop accidental clicking on html
	$("body").click(function(e){if (e.target.nodeName === "A") 	e.preventDefault();	});
		
	window.onunload = function() {		
		saveState();	
		if( confirm("Do you want to save?") ) 
			saveAll();	
	};
		
	$(document).keypress(function(e) {
		//save shortcut
		if (e.ctrlKey) {
			if(e.which == 115) {
				e.preventDefault();
				saveAll();
			}		
		}	
	});
		


	
	/****************************/
	/* WINDOWS SETUP            */
	/****************************/
		
	$("#tEdCssWindow").resizable({
		alsoResize: "#tEdCss", //tried moving this to the stop event but on a large css doc it still dragged slowly
		start: hideForMove,
		stop: function(){
			$(this).css("position", "fixed");
			showAfterMove();
		}
	});	
	
	$("#tEdHtmlWindow").resizable({
		alsoResize: "#tEdHtml",
		start: hideForMove,
		stop: function(){
			$(this).css("position", "fixed");
			showAfterMove();
		}
	});	
	
	$("#tEdCssWindow").draggable({
		handle: $("#tEdCssWindow .tEdHandle")[0],
		start: hideForMove,
		stop: function(){
			$(this).css("position", "fixed");
			showAfterMove();
		}
	});
	
	$("#tEdHtmlWindow").draggable({
		handle: $("#tEdHtmlWindow .tEdHandle")[0],
		start: hideForMove,
		stop: showAfterMove
	});
	
	//Bring windows to top
	$("#tEdCssWindow").mousedown(function() {
		$(this).css("z-index", 30000);
		$("#tEdHtmlWindow").css("z-index", 28000);
	
	});
	$("#tEdHtmlWindow").mousedown(function() {
		$(this).css("z-index", 30000);
		$("#tEdCssWindow").css("z-index", 28000);
	});	

	//Maximise on double click
	$(".tEdHandle").dblclick(function() {	
		$window = $(this).parent();		
		
		if (!$window.data("maximised") ) {	
		
			//store original pos
			$window .data("left", $window.css("left"))
					.data("top", $window.css("top"))
					.data("width",  $window.width())
					.data("height", $window.height())
					.data("maximised", true)//mark as maximised
					
					//maximise window
					.width(getViewPortDimensions().width)
					.height(getViewPortDimensions().height)
					.css({
						"left": "0",
						"top": "0"
					})
					.resizable("disable")
					.draggable("disable");
					
		//restore window
		} else {
			$window.css({
					"left": $window.data("left"),
					"top" :$window.data("top")
				})
				.width( $window.data("width"))
				.height($window.data("height"))
			    .data("maximised", false)
			    .resizable("enable")
				.draggable("enable");
		}
			
		//set inner div size
		$window.find("#tEdHtml, #tEdCss").width($window.width() -32 ).height($window.height() -50);	
	});
	
	
	
	
	
	
	//this slows scolling down! must move it another way, scroll the div rather than use margin
	$css.scroll(function() {	
		cssNumbers.scrollTop = $css[0].scrollTop;			
	});
	
	$html.scroll(function() {
		htmlNumbers.scrollTop = $html[0].scrollTop;
	});	
	

	//On lose focus apply syntax highlighting   
	$("#tEdHtml").blur(function() {
		
	});		

	$(".tEdClose").click( function() {
		$(this).parent().fadeOut("fast");
	});
	
		
	/****************************/
	/* MAIN MENU EVENTS         */
	/****************************/
	
	//hide (Control + H)
	$(window).keypress(function(e) {
	    if(e.ctrlKey && e.which == 104) {
	        e.preventDefault();	       
	        if( $("#tEd:visible").length > 0) {
	            $("#tEd").hide();
	        } else {
	            $("#tEd").show();
	        }
	    }        
	});
	
	$("#tEdReset").click(function(e) {
		e.preventDefault();
		resetPositions();
	});

	$("#tEdOpacity").click(function(e) {
		e.preventDefault();
		var opacity = prompt("Enter new opacity: 0-1", $("#tEdHtmlWindow").css("opacity"));
		$("#tEdHtmlWindow").fadeTo("slow", opacity);
		$("#tEdCssWindow") .fadeTo("slow", opacity);
	});

	$("#tEdCompact").toggle(function(e) {
		$("#tEdHtmlMenu, #tEdSheetsMenu, .tEdHandle, .tEdClose, .tEdStatus").hide("slow");
		$(".tEdLineNumbers").animate({
			"top": "2px"
		},"slow");
		$("#tEdHtmlWindow, #tEdCssWindow").animate({
			"height": "-=46px"
		},"slow");	
	}, function(e) {		
		$("#tEdHtmlMenu, #tEdSheetsMenu, .tEdHandle, .tEdClose, .tEdStatus").show("slow");
		$(".tEdLineNumbers").css({"top": ""});
		$("#tEdHtmlWindow, #tEdCssWindow").animate({
			"height": "+=46px"
		},"slow");
	});
	
	$("#tEdMainMenu").mouseover( function() {		
		$("#tEdMainMenu").stop().animate({"top": "0px"},"fast", "swing"); 
	});
	
	$("#tEdMainMenu").mouseout( function() {		
		$("#tEdMainMenu").stop().animate({"top": "-23px"},"fast", "swing"); 
	});
	
	$("#tEdMenuCss").click(
		function(e) {
			e.preventDefault();					
			if($("#tEdCssWindow").css("display") == "none")
				$("#tEdCssWindow").stop().fadeIn("fast");
			else	
				$("#tEdCssWindow").stop().fadeOut("fast");				
		}
	);
	
	$("#tEdMenuHtml").click(
		function(e) {
			e.preventDefault();
			if($("#tEdHtmlWindow").css("display") == "none")
				$("#tEdHtmlWindow").stop().fadeIn("fast");
			else	
				$("#tEdHtmlWindow").stop().fadeOut("fast");				
		}
	);	
		
	$("#tEdSave").click(function(e){
		e.preventDefault(); 
		saveAll();	    
	});
	
	$("#tEdSavePath").click( function(e) {
		e.preventDefault();
		localPath = prompt("Enter local website path", localPath);
	});	
	
	$("#tEdReset").click(function(e) {
		e.preventDefault();
		resetPositions();
	});
	
	$("#tEdAbout").click( function(e) {
		e.preventDefault();
		alert("tEd - template Editor - Simon Brown 2008");
	});	

	/****************************/
	/*  HTML MENU EVENTS        */
	/****************************/

	$html.showMenu({
		opacity:1,
		query: "#tEdHtmlRightClickMenu",
		zindex: 40000
	});
	$("#tEdHtmlRightClickMenu").hide();
	
		
	$("#tEdFontSize").click(function(e) { //might wan
		e.preventDefault();
		var newSize = prompt("Enter font size:", $css.css("font-size"));
		if(newSize)
			$("#tEd  #tEdCss, #tEd  #tEdHtml, #tEdCssLineNumbers, #tEdHtmlLineNumbers").css("font-size", newSize);		
	});

	//uncomplete	
	$("#tEdBackground").click(function(e) { //might wan
		e.preventDefault();
		
		var bgPath = pickFile("Pick background");
		
		if (!bgPath) {
			bgPath = prompt("Enter background URL");
		}
		
		if (typeof bgPath === "string") {
			bgPath = bgPath.convertLocalToUri();
			var pos = prompt("Background position:", "top center no-repeat");
			
			$("html").css("background", " url(" + encodeURI(bgPath) + ")" + pos);
			$("body").css("background", "none");
			$("body").fadeTo("slow", 0.5);
		}
	});
		
	$("#tEdBackgroundToggle").toggle(function(e) {
		$("body").css("opacity", 1);	
	},function(e) { 
		$("body").css("opacity", 0.5);	
	}, function() {
		$("body").css("opacity", 0);	
	});

	$("#tEdHtmlEntityInsert a").click(function(e) {
		e.preventDefault();
	    $("#tEdHtmlEntities").show();
	    log("HI")
		//populate symbols if not opened already
		if($("#tEdHtmlEntities").children().length == 1) {
			var html = "", i = 0;
			
			for(i = 0; i < entities.length; i++) {
				html += "<a href='#'  title='"+entities[i]+"'>&"+entities[i]+";</a>";				
			}
			
			$("#tEdHtmlEntities").append(html);
			
			$("#tEdHtmlEntities a").click(function(e) {
				e.preventDefault();
				e.stopPropagation();	
				$html[0].focus();
				document.execCommand("inserthtml", false, "&amp;"+e.target.title+";");
				refreshHtml();
		
			});
			
			$("#tEdHtmlEntities a.close").click(function() {
			    $("#tEdHtmlEntities").hide("slow");
			});
			
		    
		}		
		
	});

	//insert image
	$("#tEdHtmlImage").click(function(e) {
		e.preventDefault();
		var path = pickFile().convertLocalToUri();
	    insertHtml(  highlightHtml(("<img src='"+encodeURI(path)+"' alt='"+prompt("Alternative text attribute")+"' />") .encodeLtGt()    )   );		
	});	

	//treat others as inline
	
	/**
	
	
	
	
	todo: 
	1) use the following (and the stack height to change the 80 width) to add new lines
			//only use wrap within elements e.g. long <p>
		output = output.replace(/(.{1,80})( +|$\n?)|(.{1,80})/g, "$&\n"); //wrap	 http://blog.macromates.com/2006/wrapping-text-with-regular-expressions/

	2) have block elements that dont have a new line before the 2nd
	
	
	3) do not push <br /> etc to stack
	
	
	*/
	
	
  
    var blockElements  = ["address", "blockquote", "center", "dir", "div", "dl", "fieldset", "form", "isindex",
    "menu", "noframes", "noscript", "ol",  "table", "ul", "dd", "dt",  "tfoot",  "thead","tr","map", "object", 
    "script","html", "body", "head", "script", "style"],
    
    blockElementsNoContentIndent  = [ "h1", "h2", 	"h3", "h4", "h5", "h6",	 "p", "pre","li", "tbody", "th","td",	
    "button", "title"],

    emptyElements =     ["area", "base", "base", "br", "col", "frame", "hr", "img", "input", "isindex", 
    "link", "meta", "param"];
    

    
				/*		
	indentContents
	    div, fieldset, body, head, html, ul, ol, table, address, blockquote, center, script, style
	
	
	line after
	    li, p, br, link,  h1 h2 h3, h4, h5 , h6
	    
	inline , skip...
	    span, a etc
	
	//indenting textnodes inside scripts and p's ????- regepx? (\t{1,10})<script>([a-z]*)</script> , replace with <script>$1 $ 2  etc - where the first is the number of tab indents
	//no stripping of whitespace between style, script, pre etc...
	
	*/
	
	
	$("#tEdHtmlFormat").click(function(e) {
		e.preventDefault();
		
		var tokens = tokenize($html.html().stripHtml().decodeLtGt());
        
        function tokenize(html) {
    
            var node = /^(<\/?[^>]+>)/,
                textNode = /^([^<]*(?=<))/, //maybe keep inline ones in here too...
                tokens = [],
                count = 10000;  //max no. of nodes to stop looping during testing limited
                
            html = html.replace(/>\s+</g, "><");
            html = html.replace(/\n/g, "");
            while(html.length > 0) {
                
                //find a node
                if(html.match(node)) {
                    //log(html.match(node))
                    tokens.push(html.match(node)[0]);
                    html = html.replace(node, "");
                }
                
                //find a textnode
                if(html.match(textNode)) {
                    //log(html.match(textNode));
                    tokens.push(html.match(textNode)[0]);
                    html = html.replace(textNode, "");
                }         
                       
                //stop looping
                
                if(count-- < 0 || tokens.length === 0)         //perhaps (if white space)
                    break;
                      
            }
        
            //log(html);
            return tokens;
        }
        
        function cleanTokenizedWhitespace(tokens) {
            var clean = [];
            //need to not do for pre
            for(var i = 0, len = tokens.length; i<len; i++) {
                if(tokens[i].length > 0) {
                    clean.push(tokens[i]);
                }
            }
            return clean;        
        }
        
        function regExpEnd(elements, opts) {
            return RegExp("<\/?("+elements.join("|")+")", opts);
        }
        function regExpStart(elements, opts) {
            return RegExp("<("+elements.join("|")+")", opts);
        }        
        function regExpStartEnd(elements, opts) {
            return RegExp("<\/?("+elements.join("|")+")", opts);
        }
        
        
        function indentTokens(tokens) {
            var stack = [];
            function isTextNode(s) {return s[0] !== "<"}
            function isBlock(s) {   return regExpStartEnd(blockElements).test(s)}    
            function noIndentContent(s){return regExpStartEnd(blockElementsNoContentIndent).test(s)}    
            function isEmpty(s) {   return regExpStart(emptyElements).test(s)}     //e.g. br
            function isCloser(s) {  return s[1] === "/"}
            function buildTabs(n) { return (function(){var ts = ""; while(ts.length < n) ts+="\t";return ts;})()}  
            Array.prototype.peek =  function() {return this.length>0 ? this[this.length-1] : undefined;};
            
            tokens = cleanTokenizedWhitespace(tokens); 
        
            //need to not do for pre
            for(var i = 0, len = tokens.length; i<len; i++) {
                var tok = tokens[i];
                
                if(!isTextNode(tok))   console.log(tok, "  Block:", isBlock(tok),"Closer:", isCloser(tok) ,"noIndentContent: ",noIndentContent(tok) );
                //console.log("Stack: ", stack);
                //need to work out if its a closing or poening
                
                //a text node inside an element that indents its content
                if(isTextNode(tok) && noIndentContent(stack.peek)) {
                    tokens[i] =  buildTabs(stack.length)+ tok ;                  
                }    
                    
                //empty element like a br or an img
                else if(isEmpty(tok)) { //if it is the same as the tpo level we can remvoe it from the stack and go down an indent
                    tokens[i] =  buildTabs(stack.length)+ tok +"\n" ;  
                }   
                
                //an opener of a block that does not indent its content e.g. title, li
                else if(noIndentContent(tok) && !isCloser(tok)) {
                    stack.push(tok);
                    tokens[i] =  "\n"+buildTabs(stack.length-1) + tok ;                    
                }    
                //a closer of this type               
                else if(noIndentContent(tok) && isCloser(tok)) {
                    stack.pop();  
                    tokens[i] = tok ;     //THIS CAN BE REMOVED ....     IT DOES NOFINK          
                }   
                
                
                //an opener of a block that indents its contents e.g. div, table
                else if(isBlock(tok) && !isCloser(tok)) {
                    stack.push(tok);
                    tokens[i] = "\n" + buildTabs(stack.length-1) + tok ;                    
                } 
                //a closer of this type       
                else if(isBlock(tok) && isCloser(tok)) { //if it is the same as the tpo level we can remvoe it from the stack and go down an indent
                    stack.pop();                 
                    tokens[i] = "\n" + buildTabs(stack.length) + tok;  
                }         
                
            }
        
            //maintain a stack, the depth of the stack is sthe number of indents...
            //log(tokens);
            return tokens;
        }
        
        tokens = indentTokens(tokens);	

		$html.html( tokens.join("").encodeLtGt().replace(/\n/g, "<br>") + "<br>");
	
	});


	/****************************/
	/*  HTML EVENTS             */
	/****************************/
	//http://unixpapa.com/js/key.html
	$html.keypress(function(e) {
		var letter = String.fromCharCode(e.which);		
		var sel = window.getSelection();
		log(e.which);
		
		if (e.ctrlKey) {
			//Control + G
			if (letter.toLowerCase() == "g") {
				e.preventDefault();
				gotoLine(this);
			}
						
			//Control + C
			if (letter.toLowerCase() == "c") {
				//e.preventDefault();
				//copy();
			}	
			
			//Control + V
			if (letter.toLowerCase() == "v") {
				//e.preventDefault();	
				//paste();
			}			
		} else {		
		
		    //insert tab		
		    if (e.keyCode == 9) {
			    tab(e, this);
			    cssTyped = "";
		    }
    		
		    //reset cache of what's typed
    		
								    //enter				backspace           delete/others
		    else if (letter == "<" || e.which == 13 || e.which == 8 || e.which == 0 ) {
			    htmlTyped = "";
		    }
		    else {
			    if (letter == ">" && htmlTyped.length > 0) {				
    				
				    var text = ("</" + htmlTyped.match(/[^<][^\s>]*/) + ">");
				    log("text:",text)
				    var textNode = document.createTextNode(text);
				    window.getSelection().getRangeAt(0).insertNode(textNode);	
				    htmlTyped = "";
    				
			    }
		    }
    		
    		
    		
		    htmlTyped += letter;
    		
		    if (htmlTyped == "Lorem") {
			    e.preventDefault();
			    document.execCommand("inserthtml", false, lorem);
			    htmlTyped = "";
		    } else if ( htmlTyped == "<img"  || 
		                htmlTyped == "<br"   || 
		                htmlTyped == "<br "  || 
		                htmlTyped == "<hr"   || 
		                htmlTyped == "<meta" || 
		                htmlTyped == "<link" ) { //other ones?    //should automatically add a / in if say we type <img> --> <img />
		        htmlTyped = "";		    
		    }
    		
    		
    		
    		
    		
    		
    		
    		
    		
    		
    		
		    //INDENT ON ENTER
		    if(e.keyCode == 13 && window.getSelection().anchorNode != $html[0]) {
			    //count tabs on last line		
    			
			    var current = window.getSelection().anchorNode,
				    count = 0,
				    fragment = document.createDocumentFragment(),
				    t = "";
    			
			    fragment.appendChild(current.cloneNode(true));
    			
			    while(current.previousSibling != null) {
				    current = current.previousSibling;
				    if (current.nodeName == "BR") {
					    break;
				    }
				    else {
					    fragment.appendChild(current.cloneNode(true));
				    }				
			    }
    					
			    for (var i = 0; i < fragment.childNodes.length; i++) {
				    t += fragment.childNodes[i].nodeValue;
				    //t += $(fragment.childNodes[i]).text();
			    }
    			
    			
			    if (typeof t.match(/\t/g) !== "null") {
    				
    				
				    var numTabs = t.match(/\t/g).length;
				    var tabs = "";
				    for (var i = 0; i < numTabs; i++) {
					    tabs += "\t";
				    }
				    log("Go fwd tabs:", numTabs);
				        										
				    var textNode = document.createTextNode(tabs),
					    sel = window.getSelection();								
    				
				    sel.getRangeAt(0).insertNode(textNode);			
				    sel.getRangeAt(0).insertNode(document.createElement("br"));		
				    sel.collapse(textNode, 0);
				    sel.extend(textNode, tabs.length); //extend		
    				
				    collapseToEndOfSelection();
				    e.preventDefault();		
			    }
		    }		
		}		
	});
	
	
	$html.keydown(function() {
		
	});
	
	
	
	$html.keyup(refreshHtml);
	
	

	$html.mouseover(function(e) {	
		//image preview
		if($(e.target).hasClass("tEdAttr")) {			
			var p = e.target.innerHTML,
			    src;
			if(/src=["']\w+\.(jpg|jpeg|png|bmp|gif)["']/.test(p)) {     //needs to be made more robust
			    src = p.substring(5, p.length-1);
    			imgPreview(e, src);	 			    	
			}
		}		
		
		
	});
	
	
	
			
	$css.click(function() { cssTyped = "";});	
	$css.blur(function()  { cssTyped = "";});	
	$css.focus(function() { cssTyped = "";});	
			
	$html.click(function() { htmlTyped = "";});	
	$html.blur(function()  { htmlTyped = "";});	
	$html.focus(function() { htmlTyped = "";});	

	
	
	
	

	/****************************/
	/*  CSS RIGHT CLICK MENU    */
	/****************************/	
	
	$css.showMenu({
		opacity:1,
		query: "#tEdCssRightClickMenu",
		zindex: 40000
	});
	$("#tEdCssRightClickMenu").hide();
	
	//Add rule by choosing element with mouse
	$("#tEdAddRule").click(function(e) {
		e.preventDefault();
	    function makeSelector(el) {
			var selector = "";			
			if (el.id) {
				selector += "#" + el.id;
			}
			else {
				if (el.className) {
					selector += "." + el.className;
				}
				else {
					selector += el.nodeName.toLowerCase();
				}
				
				if(el.parentNode.id) //should recursively search upwards
					selector = "#"+el.parentNode.id + " " + selector;
				else if(el.parentNode.className)
					selector = "."+el.parentNode.className + " " + selector;  
				else if(el.parentNode.parentNode.id)
				    selector = "#"+el.parentNode.parentNode.id + " " + selector;
			}
			return selector;	
		}
	   
		$("body").mouseover(function(e) {
   			var $clicked = $(e.target);				
			$clicked.css("outline", "1px solid #BCDD5A");					
			
			e.stopPropagation();
			
			$clicked.one("click", function(e){	
				$(this).css("outline", "none");	//this will remove all outline :S
				$("body").unbind("mouseover");
				
				var ruleText = makeSelector(this);
	
				var styles = prompt("Enter styles for " + ruleText);
				
				if(styles) {
					ruleText += "<br>{<br>\t" + styles.split(";").join(";<br>\t") + "<br>}";	
					$css.html($css.html() + "<br>" + ruleText);
					updateCss();
				}
				
				refreshOutline();
			});
			
			
			$clicked.mouseout(function() {
				$(this).unbind("click");
				$(this).css("outline", "none"); //should add/remove it in a cleaner way incase already a outline on it
			});		
		});	
	});	
	
	//Add rule by choosing element with mouse
	$("#tEdFindRule").click(function(e) {
		e.preventDefault();	   
	   
		$("body").mouseover(function(e) {
			if (e.target.id.length > 0) {
				
				var $clicked = $(e.target);
				$clicked.css("outline", "1px solid #BCDD5A");
				e.stopPropagation();
				
				$clicked.one("click", function(e){	
					var toFind = "#" + e.target.id;	
					log("Find: ", toFind)			
					window.find("#" + toFind);
				});
				
				
				$clicked.mouseout(function(){
					$(this).unbind("click");
					$(this).css("outline", "none"); //should add/remove it in a cleaner way incase already a outline on it
				});
			}
		});	
	});

	//todo: fix select>format, other selections like 
	$("#tEdCssFormat").click(function(e) {
		e.preventDefault();
		formatCss(e);
		
	});
	
	//todo: fix select>format, other selections like 
	$("#tEdDivOutline").click(toggleOutline);
		
	//todo: fix select>format, other selections like 
	$("#tEdOpenHtml").click(function(e) {
		e.preventDefault();	
		
		netscape.security.PrivilegeManager.enablePrivilege("UniversalFileRead");

		//var src = prompt("Enter URL", "http://localhost/ted/");		
		var file = pickFile();
		var localFile = openFile(file);
		
		$html.text(localFile);
				
		editingInclude = true;
		$(this).css({
			"background": "#FF7900",
			"font-weight": "bold"
		});		
		
		//fix up F5 to refresh the iframe
		$(window).keypress(function(e) {
			if(e.keyCode == 116) {					
				e.preventDefault();
			}
			
		});
		
		
		
	});
	
	
	
	
	
	
	
	/****************************/
	/*  CSS  MOUSE EVENTS       */
	/****************************/	
	
	function sizeMode(e) {
        e.preventDefault();
		if($size.html() == "0") $size.html("0px");
		if(e.keyCode == 38) {
			//up key increment
			$size.text(ss.fn.incrementValue($size.text(), 1));
		} else if (e.keyCode == 40) {
			//down key decrement
			$size.text(ss.fn.incrementValue($size.text(), -1));
			//remove keyb events
		} else if (e.keyCode == 27 || e.keyCode == 13 )  {
			$size.attr("style","");
			$size.unbind("keypress", sizeMode);
			cssSizeMode = false;
		}
	}
	
	$css.dblclick(function (e) {		
		
		//test the editiblity of size and colour
		if($(e.target).hasClass("tEdSize")) {	
		    cssSizeMode = true;
		
			$size = $(e.target);
			$size.css("background", "#ccc");
			
			$css.keypress(sizeMode);
		}
		
		//not complete: pick an image 
		if($(e.target).hasClass("tEdUrl")) {	
		
			$(e.target).dblclick(function() {     //in html look for src="[^|"]+"
				$(this).html(pickFile());	
			});		
			
		}		
	
		if( $(e.target).hasClass("tEdColour") ) {
		
		
		/*   need some functions for crawling back and fowards to find out what selector it is etc  
		
		    var property = "";
		    var currentNode = e.target.parentNode.previousSibling;
		    //search until finds e.g. "background:" etc on this line
		    while(!/\w\s{3,20}:/.test(currentNode.nodeValue) && currentNode.nodeName != "BR") {
		        log("testing", currentNode);
		        currentNode = currentNode.previousSibling;
		    }
		    log(currentNode)
		    property = currentNode.nodeValue

		    log(e.target.parentNode.previousSibling.nodeValue); //does not work with mutli things yet
		    
		    
		    */
		    
		    
		    
		    
			var $color = $(e.target);
			$("#tEdColourPicker").colorpicker({
				change: function(e, ui) {				   
				
					$("#tEdColourPicker").val(ui.hex);
					$color.text("#"+ui.hex);
					//ss("."+e.target.className).property("color", $color.text());      //in real time update the rule ----------- NEEDS WORK
					ss(getCurrentRuleSelector()).property("color", $color.text()); 					
					function getCurrentRuleSelector() {return "";}//need to work out what selector it is currently in
				},
				submit: function(e, ui){
					$("#tEdColourPicker").val(ui.hex);
					$color.text("#"+ui.hex);
					$("#tEdColourPicker").fadeOut("fast").hide();
				},
				flat: true, //turning on screws loading css  up...
				color: $color.text()
			});
			var left = e.target.offsetLeft+"px",
			    top  = e.target.offsetTop +"px";
			
			$("#tEdColourPicker").css({top: top, left: left});
			$("#tEdColourPicker").hide();	
			$("#tEdColourPicker").draggable();
			$("#tEdColourPicker").fadeIn("fast");							
		}		
	});
	
	$css.mouseover(function(e) {	
		//image preview
		if($(e.target).hasClass("tEdUrl")) {
			var p = e.target.innerHTML;
			var src = p.match(/[^("']*\.(gif|jpg|jpeg|png|bmp|tiff|)/)[0];		
			
			//load img preview and dimensions
			imgPreview(e, src);	 
		}		
		
		//colour preview	
		if( $(e.target).hasClass("tEdColour") ) {	
			$(e.target).append("<span class='tEdPreview' style='background:"+$(e.target).text()+"' />");		
			$(e.target).one("mouseout", function() {
				$(e.target).find("span.tEdPreview").remove();
			});
		}
	});
	
			
	$css.click(function() { cssTyped = "";});	
	$css.blur(function()  { cssTyped = "";});	
	$css.focus(function() { cssTyped = "";});	

	
	/****************************/
	/*  CSS KEYBOARD EVENTS     */
	/****************************/
	$css.keyup(function() {	
		updateCss();
	});		
	
	function updateCss() {		
		//update page css	
		ss(ss.ds[currentSheet]).remove(); //need to replace the css or swap it around 
		ss($css.html().stripHtml());	
	}
	
	
	
	

			
	$css.keypress(cssKeypress);	
	function cssKeypress (e) {
	    if(cssSizeMode == true) return false;
	    
		var letter = String.fromCharCode(e.which);		
		var sel = window.getSelection();		
		
		log(letter);
		
		
		if (e.ctrlKey) {
			//Control + G
			if (letter.toLowerCase() == "g") {
				e.preventDefault();
				gotoLine(this);
			}
						
			//Control + C
			if (letter.toLowerCase() == "c") {
				//e.preventDefault();
				//copy();
			}	
			
			//Control + V
			if (letter.toLowerCase() == "v") {
				//e.preventDefault();	
				//paste();
			}		
			//Control + X
			if (letter.toLowerCase() == "x") {
				//e.preventDefault();	
				//copy();
				//remove selected...
			}	
				
		} else {
			/* TAB */
	        if (e.keyCode == 9) { 
			    tab(e, this);	
			}    
			
			
			/* AUTOCOMPLETE */
			
			
			    
		    /* BACKSPACE*/
    			
		    //simple auto complete code	
		    //log(e.keyCode);
		    
		    else if (e.which === 8 && cssTyped.length > 0) {//backspace
			    cssTyped = cssTyped.substring(0, cssTyped.length - 1);			
		    }

		    // SET TYPE OF DICT VIA KEYS 
		               //enter                            
		    else if (e.which == 13 || letter == ";" || letter == ":" || letter == "{" || letter == "}" || letter == " ") {
			    log("cssIndentNextLine", cssIndentNextLine);
			    
			    
			    if (letter == ";") { 
				    currentAutoCompleteList = cssKeywords;     //need to do a case/state thing
				    collapseToEndOfSelection();
			    }
			    else if (letter == ":") {
				    currentAutoCompleteList = cssValues;
				    collapseToEndOfSelection();
			    }
			    else if ( letter == "{" ) {
				    currentAutoCompleteList = cssKeywords;
				    cssIndentNextLine = true; 
			    }   
			    else if ( letter == "}" ) {
			        //remove indent before it
			        backTab(e, $css[0]);
				    cssIndentNextLine = false;
			    }   
			    
			    //Enter key         
	            else if (e.which == 13) {
	                //Indent the next line after a {
	                if( cssIndentNextLine ) {
	                     setTimeout(function() {tab(e, this)}, 0);
                    }
	            }
	            
	            cssTyped = "";
	            
		    // ANY OTHER  
		    } else {
			    cssTyped += letter;
    						
	
    			
			    var text =  autocomplete(cssTyped, currentAutoCompleteList)[0];
			    if (text) {
                    //remove current contents				
                    removeSelectedContents();		
			    
				    e.preventDefault();
    						
				    var textNode = document.createTextNode(text),
					    sel = window.getSelection();				
    				
				    sel.getRangeAt(0).insertNode(textNode);				
				    sel.collapse(textNode, 0);
				    sel.extend(textNode, text.length); //extend			
    				
			    }			
    			
		    }
        }		

	}
	
	
	
	
}//EO INIT




/****************************************************************/
/* FUNCTIONS                                                    */
/****************************************************************/	

/****************************/
/* EDIT                     */
/****************************/
//https://developer.mozilla.org/En/DOM/Selection
//https://developer.mozilla.org/en/DOM/range

function insertText(text) {
	var t = document.createTextNode(text);
	window.getSelection().getRangeAt(0).insertNode(t);		
	//select t
	var sel = window.getSelection();
	sel.extend(t, text.length);	
	collapseToEndOfSelection();
}

function insertHtml(html) {
	var range = window.getSelection().getRangeAt(0)
	var documentFragment = range.createContextualFragment(html);
	var test = range.insertNode(documentFragment);
	range.setEndAfter(window.getSelection().anchorNode.nextSibling);           //CANT GET IT TO SELECT THE FRAGMENT AND THEN COLLAPSE TO END
	collapseToEndOfSelection();
	return documentElement;
}

function collapseToEndOfSelection() {
	window.getSelection().collapse( window.getSelection().focusNode,  window.getSelection().focusNode.nodeValue.length );
}

function selectNode(n) {	 //doesn't use n???????
	var sel = window.getSelection();
	log(sel)
	sel.extend(sel.anchorNode, 1);	
}

function removeSelectedContents() {
	window.getSelection().getRangeAt(0).deleteContents();
}

//get array of all the multiple selectins (e.g. selected via control)
function getAllRanges() { 
	ranges = [];
	
	for(var i = 0; i < sel.rangeCount; i++) {
		log(sel.getRangeAt(i))
		ranges[i] = sel.getRangeAt(i);
	}

	return ranges;
}

	
	
function gotoLine(el) {
	var lineNum = prompt('Goto line number:'),
		lineBr = $(el).find("br")[lineNum];
	$(el)[0].scrollTop = lineBr.offsetTop - (parseInt($(el).css("line-height")) *4);
	//need to select section..
	//and then collapse it
	
	//lineBr.select();
	//lineBr.setSelectionRange(0,0);


	collapseToEndOfSelection();				
}

function backTab(e, el) {
	var n = window.getSelection().anchorNode;
	log("anchor", window.getSelection().anchorNode);
	
	var n = window.getSelection().anchorNode;
	if (n.nodeName == "#text") {
		log("last letter", n.textContent[n.textContent.length - 1])
		if (n.textContent[n.textContent.length - 1] == "\t") {
			n.textContent = n.textContent.substring(n.textContent.length)
		}
	}
}

function tab(e, el) {
	//multitab
	e.preventDefault();		
	
	if (e.shiftKey) {
		backTab(e, el);
	}
	else {
	
		//tab
		var breaks = $(el).find("br"), changed = false;
		breaks.each(function(){
			if (window.getSelection().containsNode(this, false)) {
				log("hi", this, "selected");
				var tab = document.createTextNode("\t");
				this.parentNode.insertBefore(tab, this.nextSibling);
				changed = true;
			}
		})
		//?
		if (changed == false) {
			insertText("\t");
			collapseToEndOfSelection();
			
		}
		
	}
}	
		


//https://developer.mozilla.org/En/Using_the_Clipboard
function copy() {
	log("copying, blocked, need to vet");				
	netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
	const gClipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"].  
	getService(Components.interfaces.nsIClipboardHelper);  
	gClipboardHelper.copyString( window.getSelection().toString());  
	
}

function paste() {
	log("Blocked pasting, need to vet");	
	netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
	var clip = Components.classes["@mozilla.org/widget/clipboard;1"].getService(Components.interfaces.nsIClipboard);  
	if (!clip) return false;  
	var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);  
	if (!trans) return false;  
	trans.addDataFlavor("text/unicode");  
	clip.getData(trans, clip.kGlobalClipboard);  				  
	var str       = new Object();  
	var strLength = new Object();  				  
	trans.getTransferData("text/unicode", str, strLength);  		
	if (str) str       = str.value.QueryInterface(Components.interfaces.nsISupportsString);  
	if (str) pastetext = str.data.substring(0, strLength.value / 2);  
	
	//does not paste over highlighted text
	removeSelectedContents();
	insertHtml(pastetext.encodeLtGt());			
}

function autocomplete(f, list) {
	var output = [];
	for (var i = 0; i < list.length; i++) 
		if(new RegExp(ss.fn.regExpEscape("^"+f)).test(list[i]))
			output.push(list[i]);
	
	return output;
}

/****************************/
/* CSS                      */
/****************************/

//Manage css tabs
function switchCssTab(i) {
	saveCurrentSheet(); 	//save sheet to array
	currentSheet = $(this).data("sheetIndex"); 		//get the next sheet index		
	currentSheet = i;
	openCss(sheets[currentSheet]);
}

function saveCurrentSheet() {
	sheets[currentSheet] = $css.html().stripHtml()
								      .replace(/<br>|<br\s*\/>/g, "\r\n")	
								      .decodeLtGt();
}



/****************************/
/* WINDOW LOAD TEXT         */
/****************************/	
	
function openCss(css) {
	var rules, comments, i, keys, values, selectors;

	$("#tEdCssWindow .tEdHandle").html("tEd Css - " + sheetsHref[currentSheet].substr(8).replace(/%20/, " "));
	
	$("#tEdSheetsMenu a").removeClass("selected");	
	$("#tEdSheetsMenu a").eq(currentSheet).addClass("selected");	
	$css.html(css.replace(/\r\n|\n/g, "<br>"))
	
	updateLineNumbers();
	simpleHighlight( $css[0], highlightCss, 50 );
	log("open css");
	
}

function openHtml(newPath) { //no refresh so the overlay doesn't get wiped out at the start
	htmlPath = typeof newPath === "undefined" ? location.pathname : newPath;
	
	var theHtml = $.ajax({
		url: 	htmlPath,      //http://developer.mozilla.org/en/Cross-Site_XMLHttpRequest
		async: 	false
	}).responseText;
	
	setHtmlTitle();
				
	theHtml = encodeHtmlBrackets(theHtml);
	theHtml = theHtml.replace(/\r\n|\n/g, "<br>").encodeEntities();
	

    $html.html(theHtml+"<br>"); //add an extra br to highlight the last line (oops if its deleted)
    refreshOutline();	   

	    
	
	updateLineNumbers();
	
	simpleHighlight( $html[0], highlightHtml, 30 );
}

//takes html from editible window and gets teh head and body innerhtml from that text and puts it in the document
function loadHtml(html) {	


	html = html.stripHtml()	//strip highlighting
			   .decodeLtGt();
	
    //strip script tags    
    html = html.replace(/<script[^>]*>[\W\w]*<\/script>/gi, "");
	
	
	var headHtml  = html.match(/<head[^>]*>[\w\s\W]*(<\/head>)/),
		bodyHtml  = html.match(/<body[^>]*>[\w\s\W]*(<\/body>)/); // for if has an id
	
	//on error
	if(!bodyHtml) {
		return false;	
	}
		
	headHtml = headHtml[0];
	bodyHtml = bodyHtml[0];
	
	headHtml = headHtml.substring(7, headHtml.length-7);
	bodyHtml = bodyHtml.substring(7, bodyHtml.length-7);
		
	//$("head").html(headHtml); breaks at the mo
	$("body").html(bodyHtml);
}



/****************************/
/*FORMATTING & HIGHLIGHTING */
/****************************/	
		
function imgPreview(e, src) {
    var img = new Image();	
    img.src = src;
    log(img.naturalWidth, img);
    var $span = $("<span class='tEdImgPreview'><img src='"+ src + "' /><span></span></span>")
    $(e.target).append($span);			
    img.onload = function() {$span.find("span").text(img.naturalWidth+"x"+img.naturalHeight); };
	
    $(e.target).one("mouseout", function() {
        $(e.target).find("span.tEdImgPreview").remove();			
    });		
}

function simpleHighlight(ed, highlightFunc, timeout) {
	var lineByLine = setTimeout(doLine, timeout),
		changed = true,	
		stack = [],
		current;
	
	//events //need a mouse up
	$(ed).bind("keypress", change);
	$(ed).bind("mouseup", change);
	

	function change(e) {
		clearTimeout(lineByLine);
		current = window.getSelection().focusNode;///////start on where its been changed- testing /./ what if its not inside the editor?
		
		if(current===$("body")[0]) current = ed.firstChild;	    
		
		if(current === ed) current = ed.firstChild; //for auto highlight timeout above
		//log("Start highlight at" , current);
		if(window.getSelection().isCollapsed) lineByLine = setTimeout(doLine, timeout);		
	}

	function doLine() {
		stack = [];
		if (current) {
		
			while ( current.nodeName != "BR" && current.nextSibling ) {
				stack.push(current);
				current = current.nextSibling;
				
				if(stack.length > 400) {
					log("Line too long, breaking");
					return false;
				}
			}
			current = current.nextSibling;//skip br
			
			replaceLine(getStackText());			
			stack = [];//reset line							
			lineByLine = setTimeout(doLine, timeout);			
		}
	}

	//http://www.howtocreate.co.uk/tutorials/javascript/dombasics
	//replace bunch of elements with highlighted text elements
	function replaceLine() {
		if(cursorOnLine())
			return false;		
		
		if (window.getSelection().containsNode(stack[0], true)) {
			log("Selection contains node ", stack[0])
			return false;
		}
		
		//replace first on stack
		replace(highlightFunc(getStackText()));
		
		for (var i = 1; i < stack.length; i++) 
			stack[i].parentNode.removeChild(stack[i]);			
	}

	function replace(newHTML) {
		if ( stack[0] ) {			
			var $arr = $("<span></span>" + newHTML + "<span></span>").slice(1, -1);
			var fragment = document.createDocumentFragment();
			
			for (var i = 0; i < $arr.length; i++) 
				fragment.appendChild($arr[i]);		
			
			
			ed.replaceChild(fragment, stack[0]);			
		}
	}

	function cursorOnLine() {
		for (var i = 0; i < stack.length; i++) {
			if (stack[i] == window.getSelection().focusNode ||
				stack[i] == window.getSelection().focusNode.parentNode ||
				stack[i] == window.getSelection().focusNode.parentNode.parentNode ||
				stack[i] == window.getSelection().focusNode.parentNode.parentNode.parentNode) {					
					//log("Cursor is on this line!")
					return true;
			}
		}
		return false;
	}

	//return stack as text - needs doing properlike!
	function getStackText() {
		var t = "";
		$(stack).each(function() {			
			if (this.nodeName == "SPAN") {				
				t += $(this).html().stripHtml(); 
			}
			else {
				t += this.textContent.encodeLtGt();
			}
		});
		return t;
	}	

	setTimeout(change, 1000);
}



var	rule = /[^\s]*[^{}]+{[^}]*}/gi,  
	comment = /\/\*(.|[\r\n])*?\*\//gi,  //thanks http://ostermiller.org/findcomment.html
	selectorText =  /[^\s][^{}]+(?={)/gi,			
	key = //[\w\-]*(?=\s*:[\w# \-,!()_/ #.%]+[};])//gi,  
	value = /[^:;{}]+(?=[};])/gi, //does not match: {this:VALUE/*damn comment!*/;}
	imported = /@import[^;]*;/gi,
	media = /@media[\s\w]+{[^}]*}/gi,        //need to fix odesnt matcvh!!!!!!!!
	url = /url\(.*?\)/ig, 
	size = /(([0-9.]{1,7}(px|em|ex|in|cm|mm|pt|pc|%)|\b0\b)|\b0\b(?= ))/g, //problem with url(100px.jpg) :( should not pick it up ([\s;}] is quick fix)             
	color = /(\#[a-f0-9]{3,6}|rgb\([\w\s,0-9%]{8,18}\)|blue|red|green|yellow|purple|black|white|orange)/ig,
	//important = /!important(?=\s*\<\/span\>[;}])/g, //not working?
	important = /!important/g;

function highlightCss(css) {	

	css = stripHtml(css);
	css = css.encodeEntities();
		     //.replace(media, "<span class='tEdMedia'>$&</span>")
	//	 	 .replace(rule, "<span class='tEdRule'>$&</span>")
	//		.replace(selectorText, "<span class='tEdSelectorText'>$&</span>")							
	//		.replace(key, "<span class='tEdKey'>$&</span>")
	
	//bug: the following screws up any html entities written in comments etc: &amp; -> <span>&amp</span>;
	css = css.replace(value, "<span class='tEdValue'>$&</span>")		
		
	css = wrap(css, important, "tEdImportant");	
	css = wrap(css, color, "tEdColour");    
	css = wrap(css, size, "tEdSize");
	css = wrap(css, url, "tEdUrl");	
	
	css = wrap(css, comment, "tEdComment");	
	
    
	return css;
}


var	node = /&lt;[^!&]*&gt;/g,
	attr = /[^ ]*(?==)="[\w\s%#!:';.!?=/]*["']/g,  //DOES NOT HIGHLIGHT ' e.g. src=''    
	/*attrkey = /[^ ]*(?==)/g,
	attrvalue = /"[A-z0-9\s]*(?=")/g, //need back ref :S*/
	commentHtml = /&lt;!--[\w\s"'`¬|+!"£$%^&*()#{}:=@~,\/.]*--&gt;/g;
	
function highlightHtml(html) {
	//console.info("in", html);
	
	html = html .stripHtml()
				.wrap( node, "tEdNode")
	 			.wrap( attr, "tEdAttr") 
				.wrap( commentHtml, "tEdComment");
				
    html = html.encodeEntities();

	return html;
}




function formatCss(e) {
	
	var s = window.getSelection();
	var selection = s.toString(),//get selectted text	
		output; 
	
	log("selection",selection)
	if (selection.length > 0) {
		output = selection;		
	}
	else {
		output = $css.html().stripHtml();
	}
		
	//strip white space from between ; : { and }
	output = output.decodeLtGt()	
			.replace(/\s*(;|:|{|})\s*/g, "$1") 			//strip white space
			.replace(/\s*,\s*(?=[^}]*{)/g, ",\n")		
			.replace(/([^;])}/g, "$1;}")				//add last ; 
			.replace(/{/g, "\n{\n\t")					//add new lines before and after { 
			.replace(/;(?!})/g, ";\n\t")				//add new line and tab after ;				 
			.replace(/;}/g, ";\n}\n\n")					//add new lines before and after }
			.replace(/\n\{\n\t;\n\}/g, " {}")       	//fix any rules without styles
			.encodeLtGt()
			.replace(/\r\n|\n/g, "<br>")
	
 	//media, import, comments? , 1 liners, no styles   //make {\n}  "selector {}" again?


	//if has selection
	if (selection) {	
		removeSelectedContents();
		insertHtml(output);
	} else {
		$css.html(output);
	}
	
	
		
}


function getVisibleLineNumbers(el) {
	return [ Math.floor(el.scrollTop / parseInt($(el).css("line-height"))), 
		     Math.floor(firstVisibleLineCss + el.clientHeight /parseInt($(el).css("line-height") ))];
}

function outlineOn() {
    $("body div").css("outline", "1px dashed gray");
    outlined = true;
}

function outlineOff() {
	$("body div").css("outline", "none");
    outlined = false;
}

function refreshOutline() {
    if(outlined) {
        outlineOn();	    
    }
}

function toggleOutline() {
    log("toggle!",outlined)
    if(outlined) {
        outlineOff();
        outlined = false;
    } else {
        outlineOn();
        outlined = true;        
    }
}



/****************************/
/* TEXT FUNCTIONS           */
/****************************/
String.prototype.stripHtml = function() {
	return this.replace(/<br>/g, "\n").replace(/(<([^>]+)>)/ig, ""); //replace <br> with new lines
}

//FIX HTML ENTTIES!!!
String.prototype.encodeLtGt = function() {
	return this.replace(/>/g, "&gt;").replace(/</g, "&lt;");
}

String.prototype.decodeLtGt = function() {
	return this.replace(/&gt;/g, ">").replace(/&lt;/g, "<"); 
}

String.prototype.encodeEntities = function() {
    var out = this,
        len = entitiesReplace.length;
    for(var i=0; i<len; i++) {
        out = out.replace(new RegExp("&"+entitiesReplace[i]+";", "g"), "&amp;"+entitiesReplace[i]+";");    
    }    
	return out;
}

String.prototype.decodeEntities = function() {
    var out = this
        len = entitiesReplace.length;
    for(var i=0; i<len; i++) {
        out = out.replace(new RegExp("&amp;"+entitiesReplace[i]+";", "g"), "&"+entitiesReplace[i]+";")
    
    }
	return out;
}

/*
working only on 2 tho:
String.prototype.encodeEntities = function() {
	return this.replace(/&amp;/g, "&amp;amp;").replace(/&copy;/g, "&amp;copy;")
}
String.prototype.decodeEntities = function() {
	return this.replace( /&amp;amp;/g, "&amp;").replace(/&amp;copy;/g, "&copy;")
}

String.prototype.encodeEntities = function() {
    log(this + "\n" + this.replace(/&(\w{1,6});/g, "&amp;$&;"))
	return this.replace(/&(\w{1,6});/g, "&amp;$&;");
}
String.prototype.decodeEntities = function() {
	return this.replace( /&amp;&(\w{1,6});/g, "&$&;");
}*/


String.prototype.wrap = function(regexp, className) {
	return this.replace(regexp, "<span class='"+className+"'>$&</span>");
}
String.prototype.convertLocalToUri = function() {
	return this.replace(/\\/g, "\/").replace(/[A-Z]/, "file:///$&");		
}

		


//old
function stripHtml(html) {
	return html.stripHtml();
}

function encodeHtmlBrackets(html ) {
	return html.encodeLtGt();
}
	
function unencodeHtmlBrackets(html ) {
	return html.decodeLtGt();
}

function wrap(t, regexp, className) {	//need to prototype it like replace() does	
	return t.wrap(regexp, className);
}


	
/****************************/
/* WINDOW FUNCTIONS         */
/****************************/	
function setHtmlTitle() {
	$("#tEdHtmlWindow .tEdHandle").html("tEd Html - " + unescape(htmlPath.replace(/^\//,"")));	
}



function saveState() {
	//whats that sutff about a mini sql for storing cookie like things?	
	for(var i=0; i<windowPositions.length; i++)	{
		var sel = windowPositions[i];
		$.cookie(sel+"Left", $(sel).css("left"));
		$.cookie(sel+"Top", $(sel).css("top"));
		$.cookie(sel+"Width", $(sel).css("width"));
		$.cookie(sel+"Height", $(sel).css("height"));  
		$.cookie(sel+"ZIndex", $(sel).css("z-index"));  
		$.cookie(sel+"Display", $(sel).css("display"));  
		$.cookie(sel+"Opacity", $(sel).css("opacity"));  
	}
	
	$.cookie("htmlPath", htmlPath);
	$.cookie("currentSheet", currentSheet);	
	
	//save bool with no-length string
	if(outlined)
	    $.cookie("Outlined", outlined);  
    else
	    $.cookie("Outlined", "");  
        
		
}
function loadState() {
	try {
		for (var i = 0; i < windowPositions.length; i++) {
			var sel = windowPositions[i];
			$(sel).css("left", $.cookie(sel + "Left"));
			$(sel).css("top", $.cookie(sel + "Top"));
			$(sel).css("width", $.cookie(sel + "Width"));
			$(sel).css("height", $.cookie(sel + "Height"));
			$(sel).css("z-index", $.cookie(sel + "ZIndex"));
			$(sel).css("display", $.cookie(sel + "Display"));
			$(sel).css("opacity", $.cookie(sel + "Opacity"));
		}
		
		openHtml($.cookie("htmlPath"));
		currentSheet = ($.cookie("currentSheet"));
		outlined = $.cookie("Outlined");
	} catch(e) {
		log("State hasn't been saved before");
	}
}

function resetPositions() {
	for(var i=0; i<windowPositions.length; i++)	{
		var sel = windowPositions[i];
		$(sel).attr("style","");
	}
}

//thanks http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
function getViewPortDimensions() {
	var myWidth = 0, myHeight = 0;
	
	if (typeof(window.innerWidth) == 'number') {
		//Non-IE
		myWidth = window.innerWidth;
		myHeight = window.innerHeight;
		
	}
	else 
		if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
			//IE 6+ in 'standards compliant mode'
			myWidth = document.documentElement.clientWidth;
			myHeight = document.documentElement.clientHeight;
			
		}
		else 
			if (document.body && (document.body.clientWidth || document.body.clientHeight)) {
				//IE 4 compatible
				myWidth = document.body.clientWidth;
				myHeight = document.body.clientHeight;
			}
	
	return {
		width: myWidth,
		height: myHeight
	};	
}
	
function hideForMove() {
	if (numberOfLines > 1000) {
		$html.hide();
		$("#tEdHtmlLineNumbers").hide();
		$css.hide();
		$("#tEdCssLineNumbers").hide();
	}
}	

function showAfterMove() {
	$html.show();
	$("#tEdHtmlLineNumbers").show();	
	$css.show();
	$("#tEdCssLineNumbers").show();	
}

// cssLineNumber
//	htmlLineNumber 
function lineNumbers () {
	var cssNum,	htmlNum;
	if (Math.max(cssLineNumber, htmlLineNumber) < numberOfLines ) {
		for (var i=0; i<25; i++) {
				
			$cssNumbersInner[0].appendChild(document.createTextNode(cssLineNumber++));
			$cssNumbersInner[0].appendChild(document.createElement("br"));
			$htmlNumbersInner[0].appendChild(document.createTextNode(htmlLineNumber++));	
			$htmlNumbersInner[0].appendChild(document.createElement("br"));
		
		};
	} 

	setTimeout(lineNumbers, 100);
}

function updateLineNumbers() {
	numberOfLines = Math.max($css.find("br").length, $html.find("br").length, numberOfLines);
}

function refreshHtml() {			
	loadHtml($html.html().decodeEntities());	
	refreshOutline();	
}

/****************************/
/* IO                       */
/****************************/

function saveAll() {
	
	var localPath =  window.location.pathname.substr(1).replace(/\//g,"\\").replace(/%20/g, " ");
	
	if(confirm("Are you sure you want to save these files:\n\n"+localPath + "\n" + sheetsHref.join("\n"))) {
		//need to create a backup..... each time!!!	
		var changed = true, txt;
				
		//Html
		if(changed) {		
			txt = $html.html()
	                  .stripHtml()
					  .replace(/<br>|<br\s*\/>/g, "\r\n")	//shouldn't this go first?
					  .replace(/&gt;/g, ">")
					  .replace(/&lt;/g, "<")
					  .decodeEntities();		
					  	
			writeFile(localPath, txt);
		}
			    
	    //Css    
		saveCurrentSheet();
	    for (var s = 0; s < sheetsHref.length; s++)  {					
			var filename = sheetsHref[s].substr(8).replace(/\//g, "\\").replace(/%20/, " ");		
	    	if (changed) {
				writeFile(filename, sheets[s].replace(/<br>|<br\s*\/>/g, "\r\n")	);  //WATCH OUT FOR ANY actual <Br>s in the text...
			}
	    }
	}
}



function pickFile() {
	netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
	const nsIFilePicker = Components.interfaces.nsIFilePicker;

	var fp = Components.classes["@mozilla.org/filepicker;1"]
		           .createInstance(nsIFilePicker);
	fp.init(window, "Dialog Title", nsIFilePicker.modeOpen);
	fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText);
	
	var rv = fp.show();
	if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
		var file = fp.file;
		// Get the path as string. Note that you usually won't 
		// need to work with the string paths.			
		/*log(fp);
		log(fp.file);
		log(fp.file.path);		*/			
		return fp.file.path;
	}	
	return false;
}


//Write local text files
//where did i get this function???
//http://developer.mozilla.org/en/Code_snippets/File_I%2F%2FO has info
function writeFile(sFilePath, sFileContent) {
    try {
		netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
        var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
        file.QueryInterface(Components.interfaces.nsIFile);
        file.initWithPath(sFilePath);
        if (file.exists() == true) 
            file.remove(false);
        var strm = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
        strm.QueryInterface(Components.interfaces.nsIOutputStream);
        strm.QueryInterface(Components.interfaces.nsISeekableStream);
        strm.init(file, 0x04 | 0x08, 420, 0);
        strm.write(sFileContent, sFileContent.length);
        strm.flush();
        strm.close();
		log("Saved " + sFilePath);
    } 
    catch (ex) {
       log(ex.message);
    }
}

function openFile(path) {
	netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
	var file = Components.classes["@mozilla.org/file/local;1"]
                     .createInstance(Components.interfaces.nsILocalFile);
	file.initWithPath(path);
	
	var data = "";
	var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
	                        .createInstance(Components.interfaces.nsIFileInputStream);
	var sstream = Components.classes["@mozilla.org/scriptableinputstream;1"]
	                        .createInstance(Components.interfaces.nsIScriptableInputStream);
	fstream.init(file, -1, 0, 0);
	sstream.init(fstream); 
	
	var str = sstream.read(4096);
	while (str.length > 0) {
		data += str;
		str = sstream.read(4096);
	}
	
	sstream.close();
	fstream.close();
	return data;	
}


function getSecurity() {
	netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');	
}





/****************************/
/* DEBUG FUNCTIONS          */
/****************************/	

function startTimer (m) {
    try {
	    console.time(m);}
	catch(e){}
}

function stopTimer (m) {
    try {
	    console.timeEnd(m);	}
	catch(e){}
}


function log(m, m2) {	
    try {
    
	    if(m.nodeType)	
		    console.dirxml(m);
	    else if (m2)
		    console.log(m, m2);
	    else 
		    console.log(m);		
	}
	catch(e){}
	return m;
}








})();








